<?php

namespace eu\freeplace\core;

use eu\freeplace\core\Constants as Constants;
use Zend_Log as Zend_Log;

/**
 * <div style="font-weight:bold;">Logging based on Zend Log.</div><br/>
 *
 * The Logger has a basic Configuration in PHP-INF/configuration.xml whit the
 * following Parameters:
 *
 * <logger enable="true">
 *    <pipePhpErrorsToLogFile>true</pipePhpErrorsToLogFile>
 *    <logLevel>ERROR</logLevel>
 *    <logFile>PHP-INF/logs/application.log</logFile>
 *    <logFileSize>1</logFileSize>
 * </logger>
 *
 * logFileSize: The file size of a logfile is by default 1 MB. A internal
 * Limiter has a upper Limit of 10 MB. This limt will be needed for good
 * performance.
 *
 * logLevel: DEBUG, INFO, NOTICE, WARN, ERROR, CRIT, ALERT, EMERG
 *
 * pipePhpErrorsToLogFile: true or false - A secure param for productive
 * envioments. if this feature enable then piped all PHP error messages into the
 * Logging file and not printet out at the webbrowser.
 *
 * All this Configuration Parameters has a default fallback in the case of
 * mismatch or empty configuration. In all cases works the Application in a
 * correct state. Only by a mismatch configuration is a information label
 * printed out at the webbrowser. A empty Configuration parameter means use the
 * default -DRY and COC paradigm.
 *
 * @author Elmar Dott
 * @version 1.0
 */
class Logger {

    const CLASS_NAME = "Logger";
    private $configuration;
    
    //Singelton Pattern =============================================
    static private $instance = null;
    static public function getInstance() {
        if (null === self::$instance) {
            self::$instance = new self;
        }
        return self::$instance;
    }
    /** Private Constructor implements a Singelton. */
    private function __construct() {
        
        $errMSG  = $this->getConfiguration();
        $errMSG .= $this->getPhpLogConfiguration();
        
        $this->lookupFile($this->configuration['logFile']);

        //PHP LOGGING
        $this->phpLogging();

        // ERROR MESSAGE FOR FALSE CONFIGURATION
        if (strlen($errMSG) > 0)
            echo "<p style='margin:3px; padding:3px; border:3px solid black;
                     background-color:yellow; color:red;'>".$errMSG."</p>";

        $this->log("Calling instance of ".self::CLASS_NAME."() [Singelton]", "NOTICE");
    }
    #================================================================

    /**
     * Logging Method for Application. HAndle a Logmassage by a LogLevel.
     * LogLevels: DEBUG INFO NOTICE WARN ERROR CRIT ALERT EMERG
     *
     * @param string $message
     * @param string $level 
     */
    public function log($message, $level) {

        if($this->configuration['enableLogging'] == true) {

            try {
                $loglevel = $this->handleLogLevel($this->configuration['logLevel']);
                // LogLevel Filter from the used logmethod
                $matched_level = $this->handleLogLevel($level);
                $format = date("Y-m-d")." ".date("H:i")." (".strtoupper($level).")\t%message%".PHP_EOL;
                $logger = Zend_Log::factory(
                            array(
                                array(
                                    'writerName' => 'Stream',
                                    'writerParams' => array(
                                        'stream' => $this->configuration['logFile'],
                                    ),
                                    'formatterName' => 'Simple',
                                    'formatterParams' => array(
                                        'format' => $format,
                                    ),
                                    'filterName' => 'Priority',
                                    'filterParams' => array(
                                        'priority' => $loglevel,
                                    ),
                                )
                            )
                          );
                $logger->log($message, $matched_level);

            } catch (Exception $e) {
                error_log("Class SiteLogger() " . $e->getMessage());
            }//try - catch
        }//if
    }

    /**
     * This Method collected the Environment Parameter for Webtracking of the 
     * Client.
     *
     * @global type $utils
     * @return string Environment
     */
    public function getEnv() {
        
        global $utils;
        $env = 
          "\n###############################################################\n".
          " Get the Environment Vars: \n".
          "  IP: \t\t".$utils->getIP()."\n".
          "  Browser: \t".$utils->getBrowserType()."\n".
          "  OS: \t\t".$utils->getOS()."\n".
          " Get Webtracking Information: \n";
        return $env;
    }

    ### ########################################################################

    private function getConfiguration() {

        global $config; $configuration = ""; $errorMSG = "";
        $core = $config->core;
        
        $configuration['enableLogging'] = $core->logger['enable'];
        if ($configuration['enableLogging'] == "true") {

            // Check the allowed Parameters for LOGLEVEL
            $pattern = "/^DEBUG|INFO|NOTICE|WARN|ERROR|CRIT|ALERT|EMERG$/";
            if (preg_match($pattern, $core->logger->logLevel)) {
                $configuration['logLevel'] = $core->logger->logLevel;
                
            } else {
                $configuration['logLevel'] = Constants::DEFAULT_LOGLEVEL;
                if ($core->logger->logLevel != "") {
                    $errorMSG .= Constants::LOGGER_ERR_LOGLEVEL;
                }
            }

            //Filesize in MB - set a upper maximum limit
            $size = $core->logger->logFileSize;
            if ($size == "" || $size < 0) {
                $size = 1;
            } else if ($size > Constants::DEFAULT_MAX_FILE_SIZE) {
                $size = 1;
                $errorMSG .= Constants::LOGGER_ERR_FILESIZE;
            }
            $calculate = 1024000 * $size;
            $configuration['logFileSize'] = $calculate;

            if (strlen($core->logger->logFile) < 1) {
                $configuration['logFile'] = Constants::DEFAULT_LOGFILE;
            } else {
                $configuration['logFile'] = $core->logger->logFile;
            }
            
        }
        $this->configuration = $configuration;
        return $errorMSG;
    }

    // In a productive Enviroment should no PHP errors printet at the Webbrowser.
    private function getPhpLogConfiguration() {
        global $config; $configuration = $this->configuration; $errorMSG = "";
        $core = $config->core;

        $_pipeing = $core->logger->pipePhpErrorsToLogFile['enable'];
        if ($_pipeing == "true") {

            $configuration['pipePhpErrorsToLogFile'] = $_pipeing;
            if (strlen($core->logger->pipePhpErrorsToLogFile->phpLogFile) < 1) {
                $configuration['phpLogFile'] = Constants::DEFAULT_PHP_LOGFILE;
            } else {
                $configuration['phpLogFile'] = $core->logger->pipePhpErrorsToLogFile->phpLogFile;
            }

            $pattern01 = "/^E_ERROR|E_WARNING|E_PARSE|E_NOTICE|E_CORE_ERROR|E_CORE_WARNING|E_COMPILE_ERROR|E_COMPILE_WARNING|E_USER_ERROR|E_USER_WARNING<E_USER_NOTICE|E_STRICT|E_RECOVERABLE_ERROR|E_DEPRECATED|E_USER_DEPRECATED|E_ALL/";           
            if (preg_match($pattern01, $core->logger->pipePhpErrorsToLogFile->phpLogLevel)) {
                $configuration['phpLogLevel'] = $core->logger->pipePhpErrorsToLogFile->phpLogLevel;

            } else {
                $configuration['phpLogLevel'] = Constants::DEFAULT_PHP_LOGLEVEL;
                if ($core->logger->logLevel != "") {
                    $errorMSG .= Constants::LOGGER_ERR_PHP_LOGLEVEL;
                }
            }    

        } elseif ($_pipeing == "false") {
            $configuration['pipePhpErrorsToLogFile'] = $_pipeing;
        } else {
            $configuration['pipePhpErrorsToLogFile'] = "true";

            if ($_pipeing != "") {
                $errorMSG .= Constants::LOGGER_ERR_PHP_PIPING;
            }
        }       
        
        $this->configuration = $configuration;
        return $errorMSG;
    }
    
    private function lookupFile($file) {
        //open file
        $handler =  fopen($file, "a+");
        //grap the content
        $content = file_get_contents($file);
        //get the filesize 1 char -> 1 Byte
        $size = strlen($content);
        // when the file is empty then write a file header OR 
        // the file size is more the configured size, then delete the old 
        // content - File ROTATION to protect the diskspace. 
        if( $size < 1 || $size > $this->configuration['logFileSize']) {         
            file_put_contents($file, $this->writeHeader());
        }
        //close the file
        fclose($handler);
    }

    private function phpLogging() {
     // PHP ERROR CLASSES:   
     // E_ERROR, E_WARNING, E_PARSE, E_NOTICE, E_CORE_ERROR, E_CORE_WARNING
     // E_COMPILE_ERROR, E_COMPILE_WARNING, E_USER_ERROR, E_USER_WARNING 
     // E_USER_NOTICE, E_STRICT, E_RECOVERABLE_ERROR, E_DEPRECATED
     // E_USER_DEPRECATED, E_ALL
     
        if($this->configuration['pipePhpErrorsToLogFile']) {   
            ini_set('display_errors', 0);
            ini_set('log_errors', 1);
            $this->lookupFile($this->configuration['phpLogFile']);
            ini_set('error_log', $this->configuration['phpLogFile']);
            error_reporting($this->configuration['phpLogLevel']);

            $this->log(self::CLASS_NAME."().phpLogging(enable)", "DEBUG");
        } else {
            $this->log(self::CLASS_NAME."().phpLogging(disable)", "DEBUG");
        }   
    }

    private function handleLogLevel($logLevel) {
        $logLevel = strtolower($logLevel);
        switch ($logLevel) {
            case 'debug'  : $level = Zend_Log::DEBUG;  break;
            case 'info'   : $level = Zend_Log::INFO;   break;
            case 'notice' : $level = Zend_Log::NOTICE; break;
            case 'warn'   : $level = Zend_Log::WARN;   break;
            case 'error'  : $level = Zend_Log::ERR;    break;
            case 'crit'   : $level = Zend_Log::CRIT;   break;
            case 'alert'  : $level = Zend_Log::ALERT;  break;
            case 'emerg'  : $level = Zend_Log::EMERG;  break;
            default       : $level = Zend_Log::ERR;    break;
        }
        return $level;
    }

    private function writeHeader() {
                return
"################################################################################
######                           The EMCS Logfile                         ######
################################################################################\n\n";
    }

}//CLASS

?>
